package connect4;
import java.util.ArrayList;

public class Connect4Model {
	public static final int HEIGHT = 6;
	public static final int WIDTH = 7;

//	private int lastPiecePlaceRow ;
//	private int lastPiecePlaceColumn ;
//	private Piece currentPiece ;
	private ArrayList<ArrayList<Piece>> gameData = new ArrayList<ArrayList<Piece>>();
    private final int[] firstAvailableRow;

    public Connect4Model() {
        firstAvailableRow = new int[WIDTH];
    	initBoardData();
    }
	public ArrayList<ArrayList<Piece>> getGameData() {
		return gameData;
	}

	public void setBoardData(ArrayList<ArrayList<Piece>> chessBoardData) {
		this.gameData.addAll(chessBoardData);
	}

	public void initBoardData(){
		ArrayList<ArrayList<Piece>> twoDArray = new ArrayList<ArrayList<Piece>>();
		for(int i = 0; i < HEIGHT; i++){
			ArrayList<Piece> eachRowData = new ArrayList<Piece>();
			for(int j = 0; j < WIDTH; j++){
				eachRowData.add(j, Piece.EMPTY);
			}
			twoDArray.add(eachRowData);
		}
		gameData.clear();
		gameData.addAll(twoDArray);
        for (int col = 0; col < WIDTH; col++) {
            firstAvailableRow[col] = HEIGHT - 1;
        }
	}
	
    public boolean isColumnAvailable(int column) {
        return firstAvailableRow[column] != -1;
    }

    public int getFirstAvailableRow(int column) {
        return firstAvailableRow[column];
    }

    public Piece[][] getGrid() {
        Piece[][] grid = new Piece[HEIGHT][WIDTH];
        for (int row = 0; row < HEIGHT; row++) {
            for (int col = 0; col < WIDTH; col++) {
                grid[row][col] = gameData.get(row).get(col);
            }
        }
        return grid;
    }

    public void mark(int col, Piece mark) throws IllegalArgumentException {
        int row = firstAvailableRow[col];
        if (row < 0) {
            throw new IllegalArgumentException(
                "Column " + (col + 1) + " is already full.");
        }
        gameData.get(row).set(col, mark);
        --firstAvailableRow[col];
    }
    
    public void set(int col, Piece mark) throws IllegalArgumentException {
        mark(col, mark);
    }

    public void unset(int col) throws IllegalArgumentException {
        int row = firstAvailableRow[col];
        if (row >= HEIGHT) {
            throw new IllegalArgumentException(
                "Column " + (col + 1) + " is already empty.");
        }
        row = ++firstAvailableRow[col];
        gameData.get(row).set(col, Piece.EMPTY);
    }
	
    public Piece findPieceByGivenPos(int row, int col){
		if(getGameData().get(row).get(col)==Piece.WHITE){
			return Piece.WHITE;
		}else if(getGameData().get(row).get(col)==Piece.BLACK){
			return Piece.BLACK;
		}else{	
			return Piece.EMPTY;
		}
    }
    
	public Piece whoseTurn(){
		int numberOfWhiteChess = 0;
		int numberOfBlackChess = 0;
		for(ArrayList<Piece> eachRowData : getGameData()){
			for(Piece chess : eachRowData){
				if(chess == Piece.WHITE){
					numberOfWhiteChess++ ;
				}
				if(chess == Piece.BLACK){
					numberOfBlackChess++ ;
				}
			}
		}
		if(numberOfWhiteChess <= numberOfBlackChess ){
			return Piece.WHITE;
		}
		return Piece.BLACK;
	}
	
	public void placeChess(String key){
		Piece chess = null;
		if(whoseTurn() == Piece.WHITE){
			chess = Piece.WHITE;
		}else{
			chess = Piece.BLACK;
		}
		int indexOfXPos = Integer.valueOf(key) - 1;
		for(int i = HEIGHT - 1; i >=0 ; i--){
			if(getGameData().get(i).get(indexOfXPos).equals(Piece.EMPTY)){
				getGameData().get(i).set(indexOfXPos, chess);
//				this.lastPiecePlaceColumn = i ;
//				this.lastPiecePlaceRow = indexOfXPos ;
				break;
			}
		}
	}
	
	public Result checkResult(){
		Result result = checkHorizontal2();
		if(result == Result.UNFINISH){
			result = checkVertical2();
			if(result == Result.UNFINISH){
				result = checkDiagonal2();
				if(result == Result.UNFINISH && !gameData.get(0).contains(Piece.EMPTY)){
					result = Result.DRAW;
				}
			}
		}
		return result;		
	}

//	public Result checkHorizontal(){
//		currentPiece = gameData.get(lastPiecePlaceColumn).get(lastPiecePlaceRow);
//		
//		//this value have to continue after left side check,and pass to right side check
//		int samePieceInRow = 0; //not include the last one
//		
//		//check left side piece if there have same piece for 3 times
//		for(int leftSidePiece = lastPiecePlaceRow - 1; leftSidePiece >= (lastPiecePlaceRow - 3) ; leftSidePiece-- ){
//			if(leftSidePiece < 0 ){break;}
//			if(gameData.get(lastPiecePlaceColumn).get(leftSidePiece)==currentPiece){
//				samePieceInRow++;
//				if(samePieceInRow >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				break;
//			}
//		}
//		//check right side piece if there have same piece for 3 times
//		for(int rightSidePiece = lastPiecePlaceRow + 1; rightSidePiece <= Connect4Panel.getWidth() ; rightSidePiece++ ){
//			if(rightSidePiece > Connect4Panel.getWidth() -1 ){break;}
//			if(gameData.get(lastPiecePlaceColumn).get(rightSidePiece)==currentPiece){
//				samePieceInRow++;
//				if(samePieceInRow >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				break;
//			}
//		}
//		return Result.UNFINISH;
//	}
	
	public Result checkHorizontal2() {
		Result result = Result.UNFINISH;
		for (int j = gameData.get(0).size() - 4; j >= 0; j--) {
		    for (int i = 0; i < gameData.size(); i++) {
				if (gameData.get(i).get(j) == gameData.get(i).get(j+1) && 
				    gameData.get(i).get(j+2) == gameData.get(i).get(j+3) &&
				    gameData.get(i).get(j+1) == gameData.get(i).get(j+2) &&
				    gameData.get(i).get(j) != Piece.EMPTY) {
					if (gameData.get(i).get(j) == Piece.BLACK) {
						result = Result.BLACKWIN;
					} else {
						result = Result.WHITEWIN;
					}
				}
		    }
		}
		return result;
	}
	
//	public Result checkVertical(){
//		//check down side piece if there have same piece for 3 times
//		//no up side check needed
//		int samePieceInColumn = 0;
//		for(int downSidePiece = lastPiecePlaceColumn + 1; downSidePiece <= Connect4Panel.getHeight() ; downSidePiece++ ){
//			if(downSidePiece > Connect4Panel.getHeight() -1 ){break;}
//			if(gameData.get(downSidePiece).get(lastPiecePlaceRow)==currentPiece){
//				samePieceInColumn++;
//				if(samePieceInColumn >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				break;
//			}
//		}
//		return Result.UNFINISH;
//	}
	
	public Result checkVertical2() {
		Result result = Result.UNFINISH;
		
		for (int i = gameData.size() - 4; i >= 0; i--) {
		    for (int j = 0; j < gameData.get(0).size(); j++) {
				if (gameData.get(i).get(j) == gameData.get(i+1).get(j) && 
				    gameData.get(i+2).get(j) == gameData.get(i+3).get(j) &&
				    gameData.get(i+1).get(j) == gameData.get(i+2).get(j) &&
				    gameData.get(i).get(j) != Piece.EMPTY) {
					if (gameData.get(i).get(j) == Piece.BLACK) {
						result = Result.BLACKWIN;
					} else {
						result = Result.WHITEWIN;
					}
				}
		    }
		}

		return result;
	}
	
//	public Result checkDiagonal(){
//		//check \ diagonal
//		int samePieceInDiagonal = 0;
//		int initRow = lastPiecePlaceRow;
//		int initCol = lastPiecePlaceColumn;
//		int getNextRow = initRow - 1;
//		int getNextCol = initCol - 1;
//		//left-up direction
//		for(int checkCount = 3; checkCount > 0 ; checkCount--){
//			if(getNextRow < 0 || getNextCol < 0 ){break;}
//			if(gameData.get(getNextCol).get(getNextRow)==currentPiece){
//				samePieceInDiagonal++;
//				if(samePieceInDiagonal >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				//reach boundary
//				break;
//			}
//			getNextRow--;
//			getNextCol--;
//		}
//		
//		//right-down direction
//		getNextRow = initRow + 1;
//		getNextCol = initCol + 1;
//		for(int checkCount = 3; checkCount > 0 ; checkCount++){
//			if(getNextRow > Connect4Panel.getWidth() -1 || getNextCol > Connect4Panel.getHeight() - 1){break;}
//			if(gameData.get(getNextCol).get(getNextRow)==currentPiece){
//				samePieceInDiagonal++;
//				if(samePieceInDiagonal >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				break;
//			}
//			getNextRow++;
//			getNextCol++;
//		}
//	
//		//check / diagonal
//		samePieceInDiagonal = 0;
//		initRow = lastPiecePlaceRow;
//		initCol = lastPiecePlaceColumn;
//		getNextRow = initRow + 1;
//		getNextCol = initCol - 1;
//		//right-up direction
//		for(int checkCount = 3; checkCount > 0 ; checkCount--){
//			if(getNextRow > Connect4Panel.getWidth() - 1 || getNextCol < 0 ){break;}
//			if(gameData.get(getNextCol).get(getNextRow)==currentPiece){
//				samePieceInDiagonal++;
//				if(samePieceInDiagonal >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				break;
//			}
//			getNextRow++;
//			getNextCol--;
//		}
//		getNextRow = initRow - 1;
//		getNextCol = initCol + 1;
//		//left-down direction
//		for(int checkCount = 3; checkCount > 0 ; checkCount++){
//			if(getNextRow < 0 || getNextCol > Connect4Panel.getHeight() - 1){break;}
//			if(gameData.get(getNextCol).get(getNextRow)==currentPiece){
//				samePieceInDiagonal++;
//				if(samePieceInDiagonal >= 3){
//					if(currentPiece == Piece.WHITECHESS){
//						return Result.WHITEWIN;
//					}else if(currentPiece == Piece.BLACKCHESS){
//						return Result.BLACKWIN;
//					}
//				}
//			}else{
//				break;
//			}
//			getNextRow--;
//			getNextCol++;
//		}
//		return Result.UNFINISH;
//	}

	public Result checkDiagonal2(){
		Result result = Result.UNFINISH;
		//check up-right diagonal
		for (int i = gameData.size() - 1; i >= 3; i--) {
		    for (int j = 0; j <= gameData.get(0).size() - 4; j++) {
				if (gameData.get(i).get(j) == gameData.get(i-1).get(j+1) &&
				    gameData.get(i-2).get(j+2) == gameData.get(i-3).get(j+3) &&
				    gameData.get(i-1).get(j+1) == gameData.get(i-2).get(j+2) &&
				    gameData.get(i).get(j) != Piece.EMPTY) {
					if (gameData.get(i).get(j) == Piece.BLACK) {
						result = Result.BLACKWIN;
					} else {
						result = Result.WHITEWIN;
					}
				}
		    }
		}
		
		//check down-right diagonal
		for (int i = 0; i<=gameData.size() - 4; i++) {
		    for (int j = 0; j <= gameData.get(0).size() - 4; j++) {
				if (gameData.get(i).get(j) == gameData.get(i+1).get(j+1) &&
				    gameData.get(i+2).get(j+2) == gameData.get(i+3).get(j+3) &&
				    gameData.get(i+1).get(j+1) == gameData.get(i+2).get(j+2) &&
				    gameData.get(i).get(j) != Piece.EMPTY) {
					if (gameData.get(i).get(j) == Piece.BLACK) {
						result = Result.BLACKWIN;
					} else {
						result = Result.WHITEWIN;
					}
			    }
		    }
		}
		return result;
	}

}
